perm filename MCTRST.PUB[HAL,HE]1 blob sn#127026 filedate 1974-10-29 generic text, type T, neo UTF8
.NEWSS (CONTROL STRUCTURES,CONTROL STRUCTURES)

.NEWSSS TRADITIONAL ALGOL STRUCTURES

	HAL has  many of  the traditional  ALGOL control  structures,
including the  statement,  the block,   the IF-THEN-ELSE conditional,
the WHILE loop, the FOR loop,  and the GOTO (which in HAL  is written
JUMP. JUMPs  will not be  implemented at first, because  they confuse
the flow analysis needed for maintaining planning values and because
it  is  possible to  accomplish  much  without  them).    The  simple
statement  can  be  of  several varieties:  Assignment,  declaration,
manipulation, assertions,    condition  monitoring.   The
assignment statement is of the general form 
.UNFILL 
	FROB α← A  +  (2,0,0)     ,  
.REFILL
that is, a variable name,  a left arrow,   and a suitable expression.
The types of expressions available will be discussed under the rubric
of data types.   Declarations are allowed  anywhere in the code  that
other statements  are allowed; this  facilitates typing in  a program
from a  terminal. Manipulation, the fundamental purpose of HAL,  will
be discussed fully  in the section  on motion specifications.   
Assertions are discussed in {sssref asr}.
Condition monitoring is discussed in {sssref onm}.

A block  is  a list  of statements  separated by  semicolons,
prefaced by  the reserved word BEGIN and  closed by the reserved word
END.  Blocks are used to  enclose a group of statements to form  what
syntactically  can act  as one  statement,  and provide  a means  for
keeping variables local to a piece of code.  It is possible to name a
block by  inserting its name  as a  string after  the BEGIN; this  is
useful  as a comment,  and during  debugging provides  a way  to name
blocks of code. When a block is so named, the name should be repeated
immediately after the END; this provides an easy way to insure proper
matching of BEGINs and ENDs. An example:
.UNFILL
	BEGIN "SAMPLE"
	SCALAR A, I;
	A α← 2;
	FOR I α← 1 STEP 1 UNTIL 10 DO A α← A*A;
	WHILE A > 0 DO
		BEGIN "LOOP"
		A α← A - 1;
		IF A < 5 THEN WRITE(A) ELSE WRITE(A-5)
		END "LOOP";
	WRITE("DONE")
	END "SAMPLE"

.REFILL
.NEWSSS	COBEGIN-COEND

	In addition to  these traditional structures, there  are also
some special  ones for specifying simultaneous independent execution.
The principal  device for  this  is the  COBEGIN-COEND pair,    which
brackets statements whose execution is meant to begin independently.
Each  of the statements within the  COBEGIN block will eventually get
executed, with whatever  overlapping of execution might  occur during
runtime (for example, while  one arm is moving, another statement can
be computing; several arms can  also work at the same time). The  termination
of the block occurs only when each of the  statements in the scope of
the COBEGIN has terminated.

.tsk:NEWSSS PARTIAL ORDERING OF SUBTASKS

	An assembly task is often divided into  subtasks which form a
partial order with  respect to the order of execution.  An example is
a task A which contains four subtasks, B, C, D, and E, of which B and
C must  be done before D,  and D must be  done before E, but  B and C
could  be done  in any  order.  It  is possible  in HAL  to leave the
ordering of  the  subtasks up  to  the compiler,  which will  try  to
optimize the entire  operation.  The way to  specify the example just
given is as follows:
.UNFILL
	TASK BEGIN "A"
		BEGIN "B"
		<code for task B>
		END "B";

		BEGIN "C"
		<code for task C>
		END "C";

		BEGIN "D AND E"
		PREREQUISITE "B", "C";
		<code for task D>
		<code for task E>
		END "D AND E"
	END "A"
.REFILL

	The words TASK BEGIN introduce a  "task block", which contains
a  set of statements.  These statements  may be  blocks identified by
strings and  may contain  the declaration  that  certain other  named
blocks within  the same  task are prerequisite  for the  inception of
this block.

	The order in which the statements are performed is determined
only insofar as the prerequisite conditions demand.  The compiler may
reorder them consistently with  the preconditions, and may even execute
some of the statements simultaneously  (as if there were a  COBEGIN),
if this is feasible.

	It is useful to place assertions at the beginning of the code
for any of the statements within a task; this assists the compiler in
maintaining its  world model, and  is also  used to  help decide  the
proper ordering of the tasks. It is likewise good to place assertions
at the end of each statement. (Assertions are discussed in {sssref asr}.)

.NEWSSS	EVENTS:  SIGNAL AND WAIT

	To  achieve simultaneous  coordinated  motion,   one  uses  a
special  form of  the move  commands which  will be  discussed later.
However, some  simple  synchronization  is  possible within  the  context  of
simultaneous  execution.   This  is  achieved  by means  of  explicit
events,  which can be signaled and awaited.   For every type of event
that the user wishes to use, there should be  a declaration something
like:
.UNFILL
	EVENT E1, E2, E3     .
.REFILL
Each event initially has  count 0, that is, no  signals have appeared
for it, and no process is waiting for it.  The statement
.UNFILL
	SIGNAL E1
.REFILL
increments the count associated  with event E1, and if  the resulting
count  is 0  or negative, one  of those  processes waiting for  E1 is
freed from its wait and readied for execution.  The statement
.UNFILL
	WAIT E1
.REFILL
decrements the count associated  with event E1, and if  the resulting
count  is negative,  the  process issuing  the WAIT  is  blocked from
continuing until  a  signal  comes along.    If  the count  is  0  or
positive, there is no waiting.

	An  example of  the utility  of  this construct  is inside  a
COBEGIN  block, where one  path of execution requires  that the other
path has passed some milestone.  Here is how such a use might appear:
.UNFILL
	EVENT MILESTONE;
	COBEGIN
		BEGIN "PATH 1"
		<code before the critical point>
		WAIT MILESTONE;
		<code after the critical point>
		END "PATH 1";

		BEGIN "PATH 2"
		<code in preparation for the milestone>
		SIGNAL MILESTONE;
		<code following the milestone>
		END "PATH 2"
	COEND 
.REFILL
.onm: NEWSSS ON MONITORS

	It  is  often  desired to  monitor  some  set  of  conditions
throughout a section of code.  A special kind of statement which allows
the user to do this is the ON statement.  A simple example is 
.UNFILL
	ON T >5 DO STOP YELLOW
.REFILL
 which while active will monitor the magnitude of T
and  if it should become greater than 5  will cause the yellow arm to
stop, if it  is moving.   An ON monitor  has two states: enabled  and
disabled. Generally,   an ON monitor  will be enabled as  soon as its
defining statement is  executed,   and it becomes  disabled when  its
block is exited. Also, as soon as an  ON monitor triggers, it becomes
disabled until explicitly reenabled.  Reenabling is done by executing
the statement ENABLE within the  conclusion (that is,  the  statement
following the  DO).  It  is possible to  name ON monitors;  a monitor
named  "CH" will be enabled when a  statement of the form ENABLE "CH"
is executed, and is disabled either under the  conditions named above
or when it is explicitly  turned off by a DISABLE statement.  To have
an ON monitor initially disabled, preface the ON with the word DEFER.  

	The condition which is being tested must  be a simple numeric
inequality  or equality,  possibly  using some  continually evaluated
function.  Boolean combinations are not allowed.
	Some examples of ON monitors:
.UNFILL
	"FUDGE" ON TEMPERATURE > 400 DO WRITE("BURNING");
	DEFER "WAIT" ON COOKED = 1 DO DISABLE "FUDGE";
	ON MARK > 3 DO ENABLE "WAIT";
.REFILL
	It should be  noted that this  ability to enable  and disable
monitors explicitly is  a non-structured concept; using it will often
lead to unintelligible programs.   In any  case, scope rules must  be
observed;  it is  not  legal to  enable  or disable  a  monitor in  a
parallel  or  subsidiary  block.  This  means  that  two  statements,
simultaneously executing inside a  COBEGIN block, are not  allowed to
interfere with each other's ON monitors.
	The  conclusion  of  an  ON-monitor  may  be  any  statement,
including  an entire block.   The only restriction is  that if a motion
statement is  the  only  statement  in the  conclusion,  it  must  be
surrounded by BEGIN and END.   (This is necessary at times to prevent
ambiguity.)  Here is a slightly more complex example:
.UNFILL

	ON DURATION > 5 DO
		BEGIN
		"BIND" ON FORCE(Z)>10 DO STOP YELLOW;
		ON DIST > 3 DO 
			BEGIN
			DISABLE BIND;
			VEL α← 40
			END
		END

.REFILL
	The existence of ON monitors raises this question: When is a
block  considered  to  be  finished?  It  can  happen that  all  the
executable statements have  finished,  but  some ON monitors  remain.
This situation is often sterile; nothing can happen unless one of the
conditions  happens  to  trigger,    which  may  or  may not  ever occur.
Therefore,  a block is declared finished when  no interpreters
(that is, pieces of straightforward code, exclusive of on-monitors)
 remain
active within it.  This  means that if even one ON monitor has caused
an interpreter to start executing  (to perform the statements in  the
conclusion), then the block  is not exited until that  interpreter is
done.   But a block  may be exited  while some ON  monitors are still
enabled; this automatically disables them.

	The  user must be  wary of the  relative speeds  at which her
various pieces of code in ON test conclusions get executed.   When an
ON test triggers, any initial statements of enabling or disabling are
done immediately,  but any arithmetic is scheduled to be done at some
point in the near future.  Therefore it is  not possible to guarantee
that a critical computation happen immediately.  If the user desires,
she may use  the word CRITICAL  at the start  of the conclusion,  and
UNCRITICAL at  the start of  that code which  need not  be guaranteed
immediate  execution. 
Only one occurrence of CRITICAL, at the very start of the conclusion,
and only one occurrence of UNCRITICAL are allowed.
   HAL  automatically  assumes CRITICAL  before
statements of  enabling and  disabling,   and UNCRITICAL  immediately
following.     
An example:
.UNFILL
	ON T>0 DO
		BEGIN "CONCLUSION"
		ENABLE "GOOD GUY";	COMMENT:  Assumed CRITICAL;
		T α← 3;			 COMMENT:  Assumed UNCRITICAL;
		END "CONCLUSION";
	ON S<0 DO
		BEGIN "RESULT"
		CRITICAL;  		COMMENT:  Overrides defaults;
		T α← 4;			COMMENT:  Will be done immediately;
		UNCRITICAL;		COMMENT:  End of critical region;
		DISABLE "GOOD GUY";	COMMENT:  Done eventually;
		END "RESULT"
.REFILL

.NEWSSS UNITS

	Numbers  are quite  often  used  for measurements,  and  many
different systems  of measurement exist.  The  UNITS statement serves
to inform the compiler which units are  being used.  The compiler uses its  own
system for internal consistency, and does any scaling when necessary.
The default  units, which the compiler itself  uses, are placed first
in the following lists:
.UNFILL
Time:		milliseconds, seconds, jiffies (that is, thirds: 60ths
		  of a second), minutes.
		  (The grain of the runtime is on the order of jiffies).
Distance:	centimeters, inches.
Mass:		grams, ounces, pounds, kilograms.
Angles:		radians, degrees.
Rotations:	Euler, Bolles, Taylor, Geomed. (These are explained
		  in {sssref dat}.)

	An example:
	UNITS SECONDS, DEGREES, TAYLOR;
.REFILL

.NEWSSS	COMMENTS

	As in Algol, comments are prefaced with  the word COMMENT and
terminated by a semicolon. Also, any text enclosed in curly brackets,
as in 
.UNFILL
	α{We are the hollow menα}
.REFILL
will be ignored.  The user can optionally reset the comment delimiters
from "α{α}" to whatever she wishes, by means of a require statement
such as:
.UNFILL
	REQUIRE "α%α%" COMMENT_DELIMITERS       .
.REFILL
which would cause the scanner to ignore any text between "α%" signs.

.NEWSSS	LABELS

	A LABEL  is a point  in the  program to which  a jump may  be
made.  Labels are not declared. An
example:
.UNFILL
	FOO: A α← A + 1;
	IF A < 100 THEN JUMP FOO; 
.REFILL
Labels  are in  general  useful mainly  for  debugging, and  not  for
program  control, especially  since JUMP will  not be  implemented at
first.

.NEWSSS ABORT

	Occasionally the user wishes to stipulate that if the program
ever reaches a particular point, something is hopelessly wrong.  The
statement ABORT causes the runtime to stop all moving devices and
to terminate execution.  The supervisor is informed of the halt, and
will inform the user. ABORT takes an optional string argument, which
is a message which will be given to the user if the ABORT statement
is executed.  An example:
.UNFILL
	ABORT ("I KEEP MISSING THE BOLT!")
.REFILL

.NEWSSS OUTPUT

	There are several ways that the user can request output
from HAL to the console.  As mentioned above, ABORT can print
a message during execution.  There is one other way to print a
message during execution, the WRITE statement, which
takes as arguments a list of variables and constants.
It is also legal to include a string constant in this list (there
are no string variables in HAL).  Formatting of output is automatic.
An example:
.UNFILL
	WRITE ("I think that the pump is at ",PUMP)
.REFILL

	Some pieces of code are only intended to work under
certain conditions of planning knowledge.  Such code might 
have a check to insure that its preconditions are met; if not,
it is proper to signal a compile-time error, with a message.
This is done with the COMPILE_ERROR statement, which optionally
takes a string argument, and which will halt compilation and print
the message.  One of the options the supervisor will give the user
is to proceed as if no error had been encountered.  Here is
an example:
.UNFILL
	COMPILE_ERROR("Hey!  You didn't attach the pump to the hand!")
.REFILL

	A similar statement which merely prints its message but
does not halt compilation is the COMPILE_WRITE statement, which
behaves in all respects like the runtime WRITE statement, in that
it can take variables and constants in its argument list, but where
variables are specified, the planning values will be printed.  For
example:
.UNFILL
	COMPILE_WRITE("YELLOW arm should be at",YELLOW)
.REFILL
.NEWSSS	PROCEDURES

	HAL  has  only   a  limited  capacity  for   procedures.  All
parameters  to a procedure  assume the planning  value "undefined" at
the conclusion of a procedure  call, except those which are  declared
as VALUE parameters  in the procedure heading, or those  stated to be
UNCHANGED  in the procedure  call. There is no  safeguard against the
accidental   modification  of  "unchanged"   parameters;   to   state
"unchanged" is entirely equivalent to an assertion that the parameter
has not changed its value during the execution of the procedure.  The
declaration of a procedure is this:
.UNFILL
	 type  PROCEDURE name (argument list)     ,
.REFILL
where  "type" is any datatype (and  is optional), and "argument list"
is a list of parameter names with their types.  An example:
.UNFILL
	SCALAR PROCEDURE LGTH (FRAME F1, F2; VECTOR VALUE V1);
.REFILL
This  declares that  LGTH is a procedure which returns  a scalar, and
takes as arguments two frames and one vector.  The vector is not
changed by the procedure.

	To call such a procedure:
.UNFILL
	S1 α← LGTH(FROB, UNCHANGED HOLE, VECT);
.REFILL
This further asserts that HOLE is not changed by the call.

	Assertions are essential at the start of  a procedure body to
inform  the  compiler  of  the  values  to  expect  for  the  various
arguments. Remember that trajectories planned on the basis  of highly
inaccurate planning values will not work well.
Assertions are discussed in {sssref asr}.

	As a procedure is entered,  all variables have planning value
"undefined".   Globals may be accessed,  but they also have undefined
initial  planning  value.   All  variables  which  have  explicit  or
implicit  assignments within a  procedure acquire  the value
"undefined" at the point directly after the procedure call.

	No modification  of the attach structure  is allowed inside a
procedure. The  compiler (often wrongly)  assumes that  there are  no
attachments involving variables within a procedure; to override this,
.UNFILL
	ASSERT FACT (ATTACHED F1 F2)   .
.REFILL
  Attachments are discussed in {ssref att}.

	There  are four  special  types  of procedure  calls:  A  HAL
program might wish to call a routine coded for the PDP11 or a routine
coded for the  PDP10. Likewise, a  program on the  PDP10 may wish  to
control a HAL program, or a routine on the  PDP11 may wish to request
some arm motion.

	To  achieve the  first  two  cases,   there  exist  "external
procedures" in HAL.  These are compiled into calls on either routines
in the PDP11 or  routines in the runtime  PDP10 package.  To  declare
such a  procedure: 
.UNFILL
	EXTERNAL PDP10 FRAME PROCEDURE FOO (FRAME A, B; VECTOR V)    .
.REFILL
 This declares the procedure FOO to be a procedure resident
in the runtime PDP10 package,  expected to return a frame  value, and
taking as arguments two frames  and a vector. PDP10 procedures do not
have access  to the  actual variables  sent, since  copies are  made;
therefore, all  arguments to  PDP10 procedures  are considered to  be
VALUE parameters.

	It  is  possible to  declare  untyped  (i.e., statement-like,
instead of expression-like) procedures as well.  Replace "PDP10" with
"PDP11" for procedures in the  PDP11. PDP11 procedures do have access
to  values, and therefore parameters are not automatically considered
to be VALUE.

	To achieve  the  second two  cases,   there  exist  "internal
procedures"  in HAL.   It is  not necessary to  state from  where the
procedure may be  called.   Internal procedures  must be  at the  top
level of a HAL program.   A complete HAL program is  considered to be
an untyped procedure without parameters.